feat(server): add --api-key bearer authentication - #305
Open
benwilson wants to merge 1 commit into
Open
Conversation
Require `Authorization: Bearer <key>` on every route except /health when `ft serve --api-key` (or FREETOKEN_API_KEY) is set; 401 with a WWW-Authenticate challenge otherwise. Unset, nothing changes. - The check is a middleware registered after the request-ring middleware, so it runs first: a rejected request never reaches a handler or the ring. OPTIONS passes through for CORS preflights; the CORS middleware installed at startup stays outermost. Constant-time compare. - /health stays open: liveness probes and the desktop app's load-progress polling cannot carry a header and reveal only status. - Shell mode keeps working: the attached client is handed the server's key; `ft shell` attaching to a running server reads FREETOKEN_API_KEY. - The control-plane requests of the shell client now send the same bearer the OpenAI client already sends. Closes FlashML-org#152
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
--api-keytoft serve(also read fromFREETOKEN_API_KEYwhen the flag is absent, so the key need not appear inps)/healthrequiresAuthorization: Bearer <key>; anything else is answered401with aWWW-Authenticate: Bearerchallenge and an OpenAI-shaped error bodyft shellattaching to a running server readsFREETOKEN_API_KEYdocs/cli.mdCloses #152.
Motivation
ft servecurrently has no way to require credentials, so any deployment that publishes the port beyond loopback is open, and clients that insist on a key (the report in #152) cannot be pointed at it without a reverse proxy in front. This is the minimal native path: one flag, one middleware, default unchanged — the same shape as #230 takes for TLS.Design notes
/health. The route surface includes mutating control routes (/v1/admin/prepare-stop,/v1/cache/rebuild), request history (/v1/requests) and/generateoutside/v1, so a/v1-prefix rule would leave holes./healthstays open because liveness probes (load balancers, Docker healthchecks) and the desktop app's load-progress polling cannot carry a header and it reveals only status._record_request_middleware, so Starlette runs it first — a401never lands in the request ring or a handler.OPTIONSpasses through (a CORS preflight carries no credentials);install_corsruns at startup and stays outermost, so it answers the preflight and decorates the401with CORS headers.hmac.compare_digest; the scheme is case-insensitive, whitespace around the token is not part of it./engine/*proxy does not yet forward a key to a serve it manages (it cannot launch one with--api-keytoday), so nothing changes there.Testing
PYTHONPATH=python python -m pytest tests/server -q→ 563 passed (535 before + 28 intests/server/test_api_key.py), on an RTX 3090 box with the[accel]install at this base401for a missing, wrong, truncated, over-long,Basicor bare credential;200for the matching bearer (case-insensitive scheme);/healthopen; every other route (/v1/chat/completions,/v1/messages,/v1/responses,/v1/models,/v1/stats,/v1/requests,/v1/cache/rebuild,/v1/admin/prepare-stop,/generate) gated before its handler;OPTIONSnot challenged;install_api_keyarm/disarm; the shell client sending the bearer on its control-plane requestsft serve --helplists the flag next to--host/--portI checked open and closed PRs for an existing api-key / auth implementation and found none (#152 is the open request; #230 is the adjacent TLS flag).